/* @flow */

import { isIE9 } from 'core/util/env'

import {
  extend,
  isDef,
  isUndef
} from 'shared/util'

import {
  isXlink,
  xlinkNS,
  getXlinkProp,
  isBooleanAttr,
  isEnumeratedAttr,
  isFalsyAttrValue
} from 'web/util/index'

//该方法用于根据data.attrs对象设置vnode对应的elm元素的特性。
//1）如果vnode是原生标签的虚拟dom对象，则会直接根据attrs对象设置特性。
//2）如果vnode是组件的虚拟dom对象，则除非设置inheritAttrs为false，会将attrs对象设置到组件的根元素上。
function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  //如果componentOptions选项存在，则说明当前vnode是一个组件的虚拟dom对象
  const opts = vnode.componentOptions
  //inheritAttrs属性的使用详情，可查看官方文档的介绍。
  //isDef(opts)说明是组件的Vnode对象，也就是说，只有组件对象才会校验inheritAttrs属性，
  //如果是原生标签，则会往下运行，并设置特性。
  if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) {
    return
  }
  if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
    return
  }
  let key, cur, old
  const elm = vnode.elm
  const oldAttrs = oldVnode.data.attrs || {}
  let attrs: any = vnode.data.attrs || {}
  // clone observed objects, as the user probably wants to mutate it
  //@todo 什么意思？
  if (isDef(attrs.__ob__)) {
    //通过extend方法拷贝的attrs的副本不会存在响应式数据系统，而只是简单的调用
    //attrs对象内部数据的get方法，获取get方法的返回值，并作为副本的值。
    attrs = vnode.data.attrs = extend({}, attrs)
  }

  //新增、修改属性
  for (key in attrs) {
    cur = attrs[key]
    old = oldAttrs[key]
    if (old !== cur) {
      setAttr(elm, key, cur)
    }
  }
  // #4391: in IE9, setting type can reset value for input[type=radio]
  /* istanbul ignore if */
  if (isIE9 && attrs.value !== oldAttrs.value) {
    setAttr(elm, 'value', attrs.value)
  }
  //删除不在新vnode中存在的属性
  for (key in oldAttrs) {
    if (isUndef(attrs[key])) {
      if (isXlink(key)) {
        elm.removeAttributeNS(xlinkNS, getXlinkProp(key))
      } else if (!isEnumeratedAttr(key)) {
        elm.removeAttribute(key)
      }
    }
  }
}

function setAttr (el: Element, key: string, value: any) {
  if (isBooleanAttr(key)) {
    // set attribute for blank value
    // e.g. <option disabled>Select one</option>
    if (isFalsyAttrValue(value)) {
      el.removeAttribute(key)
    } else {
      //注意，键和值都是key
      el.setAttribute(key, key)
    }
  } else if (isEnumeratedAttr(key)) {
    el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true')
  } else if (isXlink(key)) {//猜测：xlink好像是为了支持svg
    if (isFalsyAttrValue(value)) {
      el.removeAttributeNS(xlinkNS, getXlinkProp(key))
    } else {
      el.setAttributeNS(xlinkNS, key, value)
    }
  } else {
    if (isFalsyAttrValue(value)) {
      el.removeAttribute(key)
    } else {
      el.setAttribute(key, value)
    }
  }
}

export default {
  create: updateAttrs,
  update: updateAttrs
}
